<template>
  <div style="margin-bottom: 10px; position: relative; display: flex; align-items: center; gap: 12px">
    <el-input
      v-model="searchKeyword"
      placeholder="请输入地点/地址"
      clearable
      style="width: 300px"
      @focus="showDropdown = searchResults.length > 0"
      @blur="onInputBlur"
      @keyup.enter="onSearchInput"
      @input="onInputChange"
    >
      <template #append>
        <el-button icon="el-icon-search" @mousedown.prevent @click="onSearchButtonClick"
          >搜索</el-button
        >
      </template>
    </el-input>
    
    <!-- 地图类型切换组件 -->
    <div class="map-type-switcher">
      <el-switch
        v-model="isSatelliteMap"
        @change="onMapTypeChange"
        active-text="卫星"
        inactive-text="普通"
        active-color="#409EFF"
        inactive-color="#C0C4CC"
        style="--el-switch-on-color: #409EFF; --el-switch-off-color: #C0C4CC"
      />
    </div>
    
    <div
      v-if="searchResults.length > 0 && showDropdown"
      ref="dropdownRef"
      style="
        position: absolute;
        left: 0;
        top: 40px;
        width: 300px;
        z-index: 9999;
        background: #fff;
        border: 1px solid #eee;
        border-radius: 4px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        max-height: 240px;
        overflow-y: auto;
        pointer-events: auto;
      "
      @wheel="onDropdownWheel"
      @mousedown.stop.prevent
      @mouseup.stop.prevent
      @click.stop.prevent
    >
      <div
        v-for="(item, idx) in searchResults"
        :key="item.id || idx"
        @mousedown.stop.prevent="selectSearchResult(item, idx)"
        @mouseup.stop.prevent
        @click.stop.prevent="selectSearchResult(item, idx)"
        :style="{
          padding: '8px 12px',
          cursor: 'pointer',
          background: selectedSearchIndex === idx ? '#f6faff' : '#fff'
        }"
      >
        <div style="font-weight: bold">{{ item.title }}</div>
        <div style="font-size: 12px; color: #888">{{ item.address }}</div>
      </div>
    </div>
  </div>
  <div id="tencent-map" style="width: 100%; height: 400px; margin-bottom: 10px"></div>
  <div style="margin-top: 10px">
    <el-button type="primary" @click="confirmLocation" :disabled="!selected">确定 </el-button>
  </div>
</template>

<script setup lang="ts">
declare global {
  interface Window {
    TMap: any
  }
}
import { ref, onMounted, nextTick, watch } from 'vue'

const emit = defineEmits(['location-selected'])

const props = defineProps<{
  address?: string
  longitude?: number
  latitude?: number
}>()

const TENCENT_MAP_KEY = '72QBZ-BWA6B-RMHU2-N5T3U-YG3BE-K3FIU'

const selected = ref(false)
const lng = ref(0)
const lat = ref(0)
const addressRef = ref('')

const searchKeyword = ref('')
const searchResults = ref<any[]>([])
const showDropdown = ref(false)
const selectedSearchIndex = ref(-1)
const isSearchButtonClick = ref(false)
const isSatelliteMap = ref(false) // 地图类型切换状态

// 地图类型切换方法
const onMapTypeChange = (value: boolean) => {
  if (map) {
    // 动态切换地图类型
    map.setBaseMap({
      type: value ? 'satellite' : 'vector'
    })
  }
}

const dropdownRef = ref<HTMLElement | null>(null)
const onDropdownWheel = (e: WheelEvent) => {
  const el = dropdownRef.value
  if (!el) return
  const { scrollTop, scrollHeight, clientHeight } = el
  if (
    (e.deltaY < 0 && scrollTop === 0) ||
    (e.deltaY > 0 && scrollTop + clientHeight >= scrollHeight)
  ) {
    // 已到边界，阻止默认，防止地图缩放
    e.preventDefault()
    e.stopPropagation()
  }
  // 否则允许自身滚动
}

let map: any = null
let markerLayer: any = null
let mapInited = false

let debounceTimer: any = null
const onInputChange = () => {
  if (debounceTimer) clearTimeout(debounceTimer)
  debounceTimer = setTimeout(() => {
    if (searchKeyword.value.trim()) {
      showDropdown.value = true // 输入时保证下拉弹出
      onSearchInput()
    } else {
      searchResults.value = []
      showDropdown.value = false
    }
  }, 300)
}

const onSearchButtonClick = () => {
  isSearchButtonClick.value = true
  onSearchInput()
}

const markerStyle = {
  marker: new window.TMap.MarkerStyle({
    width: 25,
    height: 35,
    anchor: { x: 16, y: 32 },
    src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/markerDefault.png'
  })
}

// JSONP 工具函数
function jsonp(url: string): Promise<any> {
  return new Promise((resolve, reject) => {
    const callback = 'jsonp_callback_' + Math.random().toString(36).substr(2, 16)
    const script = document.createElement('script')
    ;(window as any)[callback] = (data: any) => {
      resolve(data)
      script.parentNode && script.parentNode.removeChild(script)
      delete (window as any)[callback]
    }
    script.src = url + (url.includes('?') ? '&' : '?') + 'callback=' + callback
    script.onerror = reject
    document.body.appendChild(script)
  })
}

// 搜索输入
const onSearchInput = async () => {
  if (!searchKeyword.value.trim()) {
    searchResults.value = []
    showDropdown.value = false
    selectedSearchIndex.value = -1
    isSearchButtonClick.value = false // 状态重置
    return
  }
  // 按官方文档完善参数
  const region = '全国'
  const page_size = 10
  const url = `https://apis.map.qq.com/ws/place/v1/suggestion?keyword=${encodeURIComponent(
    searchKeyword.value
  )}&key=${TENCENT_MAP_KEY}&region=${encodeURIComponent(
    region
  )}&page_size=${page_size}&output=jsonp`
  try {
    const res: any = await jsonp(url)
    if (res.data) {
      searchResults.value = res.data
      showDropdown.value = searchResults.value.length > 0
      // 只有点击搜索按钮时才自动跳转
      if (searchResults.value.length > 0 && isSearchButtonClick.value) {
        selectSearchResult(searchResults.value[0], 0)
      }
    } else {
      searchResults.value = []
      showDropdown.value = false
    }
  } catch (e) {
    searchResults.value = []
    showDropdown.value = false
  }
  isSearchButtonClick.value = false // 每次都重置
}

// 新增：根据地址搜索定位
async function onSearchByAddress(addr: string) {
  const url = `https://apis.map.qq.com/ws/place/v1/suggestion?keyword=${encodeURIComponent(
    addr
  )}&key=${TENCENT_MAP_KEY}&region=全国&output=jsonp`
  try {
    const res: any = await jsonp(url)
    if (res.data && res.data.length > 0) {
      const item = res.data[0]
      lng.value = item.location.lng
      lat.value = item.location.lat
      addressRef.value = item.address
      selected.value = true
      map.setCenter(new window.TMap.LatLng(lat.value, lng.value))
      if (!markerLayer) {
        markerLayer = new window.TMap.MultiMarker({
          map: map,
          styles: markerStyle,
          geometries: [
            {
              id: 'selected',
              styleId: 'marker',
              position: new window.TMap.LatLng(lat.value, lng.value)
            }
          ]
        })
      } else {
        markerLayer.updateGeometries([
          {
            id: 'selected',
            styleId: 'marker',
            position: new window.TMap.LatLng(lat.value, lng.value)
          }
        ])
      }
    }
  } catch (e) {}
}

// 监听props变化，自动定位
watch(
  () => [props.address, props.longitude, props.latitude],
  ([address, lngProp, latProp]) => {
    if (mapInited && map) {
      if (lngProp && latProp) {
        map.setCenter(new window.TMap.LatLng(latProp, lngProp))
        if (!markerLayer) {
          markerLayer = new window.TMap.MultiMarker({
            map: map,
            styles: markerStyle,
            geometries: [
              {
                id: 'selected',
                styleId: 'marker',
                position: new window.TMap.LatLng(latProp, lngProp)
              }
            ]
          })
        } else {
          markerLayer.updateGeometries([
            {
              id: 'selected',
              styleId: 'marker',
              position: new window.TMap.LatLng(latProp, lngProp)
            }
          ])
        }
      } else if (address && typeof address === 'string') {
        onSearchByAddress(address)
      }
    }
  },
  { immediate: true }
)

const onInputBlur = () => {
  setTimeout(() => {
    showDropdown.value = false
  }, 150)
}

// 选择候选项并定位
const selectSearchResult = (item: any, idx: number) => {
  showDropdown.value = false
  searchKeyword.value = item.title
  lng.value = item.location.lng
  lat.value = item.location.lat
  addressRef.value = item.address
  selected.value = true
  selectedSearchIndex.value = idx

  // 地图定位
  if (map) {
    map.setCenter(new window.TMap.LatLng(lat.value, lng.value))
    if (!markerLayer) {
      markerLayer = new window.TMap.MultiMarker({
        map: map,
        styles: markerStyle,
        geometries: [
          {
            id: 'selected',
            styleId: 'marker',
            position: new window.TMap.LatLng(lat.value, lng.value)
          }
        ]
      })
    } else {
      markerLayer.updateGeometries([
        {
          id: 'selected',
          styleId: 'marker',
          position: new window.TMap.LatLng(lat.value, lng.value)
        }
      ])
    }
  }
}

// 只在弹窗完全打开后由父组件调用
const initMap = () => {
  if (mapInited) return
  mapInited = true
  // @ts-ignore
  map = new window.TMap.Map('tencent-map', {
    center: new window.TMap.LatLng(39.98412, 116.307484), // 默认北京
    zoom: 12,
    baseMap: {
      type: isSatelliteMap.value ? 'satellite' : 'vector' // 根据切换状态动态设置地图类型
    }
  })

  map.on('click', (evt: any) => {
    const { latLng } = evt
    lng.value = latLng.lng
    lat.value = latLng.lat
    selected.value = true
    selectedSearchIndex.value = -1

    // 用 MultiMarker 显示选中点，带 styleId
    if (!markerLayer) {
      markerLayer = new window.TMap.MultiMarker({
        map: map,
        styles: markerStyle,
        geometries: [
          {
            id: 'selected',
            styleId: 'marker',
            position: latLng
          }
        ]
      })
    } else {
      markerLayer.updateGeometries([
        {
          id: 'selected',
          styleId: 'marker',
          position: latLng
        }
      ])
    }

    // 逆地址解析（用腾讯地图JS API，无CORS问题）
    // @ts-ignore
    const geocoder = new window.TMap.service.Geocoder()
    geocoder.getAddress({ location: latLng }).then((result: any) => {
      addressRef.value = result.result.address
      searchKeyword.value = addressRef.value
    })
  })
}

defineExpose({
  initMap,
  locateByAddress: (addr?: string) => {
    if (addr) onSearchByAddress(addr)
  }
})

const confirmLocation = () => {
  emit('location-selected', {
    address: addressRef.value,
    longitude: lng.value,
    latitude: lat.value
  })
}

onMounted(() => {
  nextTick(() => {
    initMap()
  })
})
</script>

<style scoped>
.map-type-switcher {
  display: flex;
  align-items: center;
  white-space: nowrap;
}

:deep(.el-switch__label) {
  font-size: 12px;
  color: #606266;
}

:deep(.el-switch__label.is-active) {
  color: #409EFF;
}

:deep(.el-switch) {
  --el-switch-on-color: #409EFF;
  --el-switch-off-color: #C0C4CC;
}
</style>
